---@class TBS.Buffer:TBS.BuffBase
---@field New fun():TBS.Buffer
local Buffer = TBS.CreateClass("Buffer","BuffBase")

local STAGE = {
    start = 1,      --开始阶段
    loop = 2,     --循环阶段
    destroying= 3,  --销毁阶段
}
function Buffer:OnCreate()
    TBS.BuffBase.OnCreate(self)
    self.cfg = nil
    self.showCfg = nil
    self.stateList = {}
    ---@type GameObject
    self.gameObject = nil
    ---@type Spine.Unity.SkeletonAnimation
    self.animation = nil
    ---@type MeshRenderer
    self.render = nil
    self.offSet = Vector3.GetCacheVec()
    self.pos =  Vector3.GetCacheVec()
    self.resName = ""
    self.LoadRequestId = 0
    self.stage = 0
    self.scale = 1
    self.audio = nil
    ---@type TBS.EffectBase
    self.effect = nil
    ---@type {during,resName,resAction,time}[]
    self.effectDataList = {}

    self.isDestroyed = false
    self.isDie = false
    self.isLoading = false
    self.callbackList = nil
end

function Buffer:OnDestroy(isClear)
    self.isDestroyed = true
    TBS.PoolMgr.CancelLoad(self.LoadRequestId)
    TBS.PoolMgr.ReturnPrefabToPool(self.resName,self.gameObject)
    self.LoadRequestId = 0
    self.gameObject = nil
    self.isDie = true
    self.resName = ""
    if self.callbackList then
        self:StartEffCallback()
        TablePool.ReleaseDeeper(self.callbackList,false)
    end
    self.callbackList = nil
    if self.effect then
        if isClear then
            TBS.EffectMgr.DestroyEffect(self.effect)
        else
            self:SetStage(STAGE.destroying)
        end
    end
    Vector3.ReturnToPool(self.offSet)
    Vector3.ReturnToPool(self.pos)
    self.offSet = nil
    self.pos = nil
    self.effect = nil
end
function Buffer:Set(buffId,overlay,casterId,targetId,during)
    TBS.BuffBase.Set(self,buffId,overlay,casterId,targetId,during)
    local actor = self:GetTarget()
    if actor then
        self.pos:SetV(actor:GetPos())
    end
    self:InitCfg()
    self:OnBuffStart()
end
function Buffer:InitCfg()
    local cfg = dataTable.getDataTableByStringId("t_collocationbuff",self.buffId)
    local showCfg = dataTable.getDataTableByStringId("t_collocationbuffshow",self.buffId)
    if not cfg then
        self.isDie = true
        logError("找不到t_collocationskill"..self.buffId)
        return
    end
    if not showCfg then
        self.isDie = true
        logError("找不到t_collocationbuffshow"..self.buffId)
        return
    end
    if showCfg.f_BuffPosition ~= "" then
        self.offSet:Set(showCfg.f_BuffPosition[1],showCfg.f_BuffPosition[2])
    else
        self.offSet:Set(0,0)
    end
    self.turnDuring = cfg.f_Continued
    self.posType = showCfg.f_BuffTarget
    self.audio = showCfg.f_BuffAudio
    if showCfg.f_BuffSize > 0 then
        self.scale = showCfg.f_BuffSize/10000
    else
        self.scale = 1
    end
    --特效
    local data = {time = 0,during = showCfg.f_BuffStartTime/1000,
                  resName = showCfg.f_BuffResources,
                  resAction = showCfg.f_BuffStart}
    table.insert(self.effectDataList,data)
    local data = {time = 0,during = 0,
                  resName = showCfg.f_BuffResources,
                  resAction = showCfg.f_BuffLoop}
    table.insert(self.effectDataList,data)
    local data = {time = 0,during = showCfg.f_BuffEndTime/1000,
                  resName = showCfg.f_BuffResources,
                  resAction = showCfg.f_BuffEnd}
    table.insert(self.effectDataList,data)
end
function Buffer:GetTarget()
    return TBS.ActorMgr.GetActor(self.targetId)
end
function Buffer:GetPosByType()
    local PosType = TBS.Config.BuffEffectPosType
    local x = 0
    local y = 0
    if self.posType == PosType.AllGroupCenter then
        x,y = TBS.Battle.GetAllLeaderCenterPosition()
    elseif self.posType == PosType.Boss then
        x,y = TBS.Battle.GetBossPosition()
    elseif self.posType == PosType.curGroupCenter then
        local actor = TBS.ActorMgr.GetActor(self.targetId)
        if not actor then
            logError(self.buffId.." buff找不到目标 "..self.targetId)
            return x,y
        end
        x,y = TBS.Battle.GetLeaderPosition(actor:GetGroupId())
    else
        local actor = TBS.ActorMgr.GetActor(self.targetId)
        if not actor then
            logError(self.buffId.." buff找不到目标 "..self.targetId)
            return x,y
        end
        x = actor:GetPos().x
        y = actor:GetPos().y
    end
    return x + self.offSet.x,y + self.offSet.y
end
function Buffer:LoadModel()
    local data = self.effectDataList[self.stage]
    if not data then return end
    if data.resName ~= self.resName then
        TBS.EffectMgr.DestroyEffect(self.effect)
        if data.resName ~= "" then
            local res = "Prefabs/Skill/"..data.resName
            local x,y = self:GetPosByType()
            self.effect = TBS.EffectMgr.CreateEffect2(self.casterId,res,data.resAction,x,y)
            self.effect:SetScale(self.scale)
        end
        self.resName = data.resName
    else
        if data.resAction ~= "" and self.effect then
            self.effect:PlayAnim(data.resAction)
        end
    end
    if self.effect then
        if data.resAction == "" then
            TBS.EffectMgr.DestroyEffect(self.effect)
            self.effect = nil
        else
            self.effect:SetAutoDestroy(self.stage == STAGE.destroying)
        end
    end
    data.time = 0
end

function Buffer:SetStage(stage,forceUpdate)
    if self.stage == stage and not forceUpdate then
        return
    end
    if self.stage == STAGE.start and stage == STAGE.loop then
        self:StartEffCallback()
    end
    self.stage = stage
    self:LoadModel()
end
function Buffer:IsDie()
    return self.isDie
end
function Buffer:SetAnim(name,isLoop)
    if not self.animation or string.IsNilOrEmpty(name) then
        return
    end
    isLoop = isLoop or false
    Util.PlayAction(self.animation,name,isLoop)
end
function Buffer:TimeEnd()

    self.isDie = true
end
---回合开始
function Buffer:TurnStart()
    --[[self.curTurnDuring = math.max(self.curTurnDuring - 1,0)
    if self.curTurnDuring == 0 then
        self.isDie = true
    end]]
end

function Buffer:Update(dt)
    TBS.BuffBase.Update(self,dt)
    self:UpdateStage(dt)
end
function Buffer:UpdateStage(dt)
    local data = self.effectDataList[self.stage]
    if not data then return end
    data.time = data.time + dt
    if data.during > 0 and data.time > data.during then
        self:SetStage(self.stage + 1)
    end
end
---实例化后，生效前调用(还未加入buff容器中)
function Buffer:OnBuffAwake()

end
---buff生效时
function Buffer:OnBuffStart()
    TBS.BuffBase.OnBuffStart(self)
    self:SetStage(STAGE.start)
    AudioManager.Play(self.audio)
end
---相同类型时刷新(更新buff层数、等级、持续时间等)
function Buffer:OnBuffRefresh(overlay)
    self.overlay = overlay
    self.curTime = 0
    self.curTurnDuring = self.turnDuring
    AudioManager.Play(self.audio)
end
---当buff销毁前(还未从buff容器中移除)
function Buffer:OnBuffRemove()
    self.isDie = true
end
function Buffer:HasStartEff()
    local data = self.effectDataList[STAGE.start]
    if not data then
        return false
    end
    return data.resName ~= ""
end
function Buffer:RegisterStartEffEndCallback(tb,callback,autoRemove)
    if self.stage > 1 then
        callback(tb)
        return
    end
    if not self.callbackList then
        self.callbackList = TablePool.Get()
    end
    for k,v in pairs(self.callbackList) do
        if v.tb == tb and v.callback == callback then
            return
        end
    end
    local temp = TablePool.Get()
    temp.tb = tb
    temp.callback = callback
    temp.autoRemove = autoRemove
    table.insert(self.callbackList,temp)
end
function Buffer:StartEffCallback()
    if not self.callbackList then return end
    local tbList = self.callbackList
    local tb = TablePool.Get()
    for k,v in pairs(tbList) do
        table.insert(tb,v)
    end
    for k,v in pairs(tb) do
        v.callback(v.tb)
        if v.autoRemove then
            self:UnRegisterStartEffEndCallback(v.tb,v.callback)
        end
    end
    TablePool.ReleaseDeeper(tb,false)
end
function Buffer:UnRegisterStartEffEndCallback(tb,callback)
    if not self.callbackList then return end
    for k,v in pairs(self.callbackList) do
        if v.tb == tb and v.callback == callback then
            table.remove(self.callbackList,k)
            TablePool.ReleaseDeeper(v,false)
            return
        end
    end
end